using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace LabyrinthProject
{
    enum CollisionType
    {
        Wall, Player, None, AI
    }

    static class CollisionDetection
    {
        #region fields
        static List<WallElement> listOfLabyrinthWalls = new List<WallElement>();

        static List<WallElement> listOfWallElementsInCollision = new List<WallElement>();

        private static int type1Collision = 0;
        private static int type2Collision = 0;

        private static CollisionType previousCollisionType = CollisionType.None;
        #endregion

        #region methods
        public static List<CollisionType> CheckCollision(Player player, Player secondPlayer, List<AI> ai)
        {
            listOfWallElementsInCollision.Clear();//ovo sam dodao jer se nebrise lista pa onda s vremenom pocne trzat

            //BoundingBox playerBoundingBox = new BoundingBox(player.Position - new Vector3(150, 0, 150), player.Position + new Vector3(150, 300, 150));
            //BoundingSphere playerBoundingSphere = new BoundingSphere(player.Position + new Vector3(0, 100, 0), 150);
            bool wallCollision = false;
            bool aiCollision = false;
            bool playerCollision = false;

            List<CollisionType> collisions = new List<CollisionType>();

            wallCollision = CheckWallCollision(player);
            playerCollision = CheckPlayerCollision(player, secondPlayer);
            aiCollision = CheckAiCollision(player, ai);

            if (wallCollision)
            {
                previousCollisionType = CollisionType.Wall;
                collisions.Add(CollisionType.Wall);
            }

            if (playerCollision)
            {
                previousCollisionType = CollisionType.Player;
                collisions.Add(CollisionType.Player);
            }

            if (aiCollision)
            {
                previousCollisionType = CollisionType.AI;
                collisions.Add(CollisionType.AI);
            }



            if (collisions.Count == 0)
            { 
                type1Collision = 0;
                type2Collision = 0;
                collisions.Add(CollisionType.None);
            }

            return collisions;
        }

        private static bool CheckWallCollision(Player player)
        {
            bool wallCollision = false;
            BoundingSphere bSphere = new BoundingSphere();
            foreach (ModelMesh mesh in player.Model.Meshes)
            {
                bSphere = BoundingSphere.CreateMerged(bSphere, mesh.BoundingSphere);
            }
            bSphere.Center = player.Position;
            //bSphere1.Radius *= 1.0f;
            bSphere.Radius = 200;
            //bSphere1.Center += player.Position;

            player.BoundingSphere = bSphere;

            for (int i = 0; i < listOfLabyrinthWalls.Count; i++)
            {
                if (listOfLabyrinthWalls[i].BoundingBox.Intersects(bSphere))
                {
                    listOfWallElementsInCollision.Add(listOfLabyrinthWalls[i]);
                    wallCollision = true;
                }
            }
            return wallCollision;
        }

        private static bool CheckPlayerCollision(Player player1, Player player2)
        {
            BoundingSphere bSphere1 = new BoundingSphere();
            foreach (ModelMesh mesh in player1.Model.Meshes)
            {
                bSphere1 = BoundingSphere.CreateMerged(bSphere1, mesh.BoundingSphere);
            }
            bSphere1.Center = player1.Position;
            //bSphere1.Radius *= 1.0f;
            bSphere1.Radius = 200f;
            //bSphere1.Center += player.Position;


           

            player1.BoundingSphere = bSphere1;


            BoundingSphere bSphere2 = new BoundingSphere();
            foreach (ModelMesh mesh in player2.Model.Meshes)
            {
                bSphere2 = BoundingSphere.CreateMerged(bSphere2, mesh.BoundingSphere);
            }
            bSphere2.Center = player2.Position;
            //bSphere1.Radius *= 1.0f;
            bSphere2.Radius = 200f;
            //bSphere1.Center += player.Position;

            player2.BoundingSphere = bSphere2;

            if (bSphere1.Intersects(bSphere2))
            {
                if (player2.cookiedPickedUp == true)
                {
                    player1.cookiedPickedUp = true;
                    player2.cookiedPickedUp = false;
                }
                else if (player1.cookiedPickedUp == true)
                {
                    player2.cookiedPickedUp = true;
                    player1.cookiedPickedUp = false;
                }
                return true;
            }
            return false;
        }

        public static bool CheckAiCollision(Player player, List<AI> ai)
        {

            BoundingSphere bSpherePlayer = new BoundingSphere();
            foreach (ModelMesh mesh in player.Model.Meshes)
            {
                bSpherePlayer = BoundingSphere.CreateMerged(bSpherePlayer, mesh.BoundingSphere);
            }
            bSpherePlayer.Center = player.Position;
            //bSphere1.Radius *= 1.0f;
            bSpherePlayer.Radius = 500f;


            BoundingSphere bSphere = new BoundingSphere();
            for (int i = 0; i < ai.Count; i++)
            {

                bSphere = GetAiBoundingSphere(ai[i].Model);

                bSphere.Center = ai[i].Position;
                bSphere.Center.Y += 50;
                bSphere.Radius = 500f;


                if (bSpherePlayer.Intersects(bSphere))
                    return true;
            }

            return false;
        }

        public static BoundingSphere GetAiBoundingSphere(Model model)
        {
            BoundingSphere boundingSphere = new BoundingSphere();


            foreach (ModelMesh mesh in model.Meshes)
            {
                boundingSphere = BoundingSphere.CreateMerged(boundingSphere, mesh.BoundingSphere);
            }

            return boundingSphere;
        }

        

        //metoda koja razrješava sudare woohoo!!1
        public static void ResolveWallCollision(Player player)
        {
            float elapsed = (float)player.gameTime.ElapsedGameTime.TotalSeconds;
            
            HandleCollision(player, listOfWallElementsInCollision, elapsed);

        }


        private static void HandleCollision(Player player, List<WallElement> listOfCollisionWalls, float elapse)
        {
            List<Vector3> listOfCollisionNormals = new List<Vector3>();


            Vector3 playerDirection = player.velocity;
            playerDirection.Normalize();

            foreach (WallElement wall in listOfCollisionWalls)
            {
                if (!wall.BoundingBox.Intersects(player.BoundingSphere)) continue;

                bool exist = false;

                if (wall.RightQuad.Plane.DotCoordinate(player.OldPosition) > 0)
                {
                    if (Vector3.Dot(playerDirection, wall.RightQuad.Normal) < 0 && !listOfCollisionNormals.Contains(wall.RightQuad.Normal))
                    {
                        exist = true;
                        listOfCollisionNormals.Add(wall.RightQuad.Normal);
                    }
                }

                if (wall.LeftQuad.Plane.DotCoordinate(player.OldPosition) > 0)
                {
                    if (Vector3.Dot(playerDirection, wall.LeftQuad.Normal) < 0 && !listOfCollisionNormals.Contains(wall.LeftQuad.Normal))
                    {
                        exist = true;
                        listOfCollisionNormals.Add(wall.LeftQuad.Normal);
                    }
                }

                if (wall.BeginQuad.Plane.DotCoordinate(player.OldPosition) > 0)
                {
                    if (exist) listOfCollisionNormals.Remove(listOfCollisionNormals.Last());

                    if (Vector3.Dot(playerDirection, wall.BeginQuad.Normal) < 0 && !listOfCollisionNormals.Contains(wall.BeginQuad.Normal)) listOfCollisionNormals.Add(wall.BeginQuad.Normal);
                }

                if (wall.EndQuad.Plane.DotCoordinate(player.OldPosition) > 0)
                {
                    if (exist) listOfCollisionNormals.Remove(listOfCollisionNormals.Last());

                    if (Vector3.Dot(playerDirection, wall.EndQuad.Normal) < 0 && !listOfCollisionNormals.Contains(wall.EndQuad.Normal)) listOfCollisionNormals.Add(wall.EndQuad.Normal);
                }
            }

            //sa ovim se postavlja odbijenje, ako je vece od 0.5
            float amount = 0.5f;
            foreach (Vector3 collisionNormal in listOfCollisionNormals)
            {
                Vector3 newVelocity = player.velocity - 2 * (player.velocity * collisionNormal) * collisionNormal;

                player.Position = player.OldPosition;
                player.velocity = player.velocity * (1 - amount) + newVelocity * amount;
                player.Position = player.Position + player.velocity * elapse;


                Vector3 tmpPos = player.Position;
                tmpPos.Y = Math.Max(tmpPos.Y, player.MinimumAltitude);
                player.Position = tmpPos;

                Matrix wrld = new Matrix();
                wrld = Matrix.Identity;
                wrld.Forward = player.Direction;
                wrld.Up = player.Up;
                wrld.Right = player.Right;
                wrld.Translation = player.Position;


                Matrix rotacija = Matrix.CreateRotationY(MathHelper.ToRadians(-90)) * Matrix.CreateRotationY(MathHelper.Pi);
                Matrix rotacija2 = Matrix.CreateRotationY(MathHelper.ToRadians(-90)) * Matrix.CreateRotationY(MathHelper.Pi);

                player.World = wrld;
                //world = rotacija2 * world;
                player.World = rotacija * player.World;

                player.World = rotacija2 * player.World;

                player.World = player.ScaleMatrix * player.World;

            }
        }

   
        public static void ResolvePlayer2PlayerCollision(Player player)
        {
            player.Position = player.OldPosition;
            player.velocity.X *= -1.5f;
            player.velocity.Z *= -1.5f;
            player.World = player.OldWorldMatrix;
            player.Up = player.OldUp;
            player.Right = player.OldRight;
            player.Direction = player.OldDirection;
        }

        public static void ResolvePlayerAICollision(Player player)
        {
            //PowerUp freeze = new PowerUp(null, null, PowerUpType.Cipela, new Vector3(0, 0, 0));
            //player.AddPowerUp(freeze);
            player.BodyAction = Action.Freezed;
        }

        public static void SetLabyrinthWalls(Labyrinth labyrinth)
        {
            foreach (WallElement element in labyrinth.ListOfWallElements)
            {
                listOfLabyrinthWalls.Add(element);
            }
        }

        public static void ClearLabyrinthWalls ()
        {
            listOfLabyrinthWalls.Clear();
        }

        #endregion
    }
}
